<!-- 组件模型详情 -->
<script setup lang="ts">
import type { BasicClassValueField } from "@@/apis/basic-data/types"
import type { BasicDataInfo, MethodField, SaveRequestData } from "@@/apis/component/type"
import type { UploadUserFile, UploadProps } from "element-plus"
import type { FormInstance, FormRules } from "element-plus"
import type { VxeTablePropTypes } from "vxe-table"
import { closeRoute } from "@/common/composables/useCloseRouteListener"
import { getModelDetail, getModelSearch, saveModelField, uploadEntityFilesApi } from "@@/apis/component"
import SelectTag from "@@/components/SelectTag/index.vue"
import { Edit } from "@element-plus/icons-vue"
import { ElMessage, ElMessageBox } from "element-plus"
import { cloneDeep } from "lodash-es"
import { v4 as uuidv4 } from "uuid"
import { computed, onActivated, onMounted, ref } from "vue"
import { useRoute, useRouter } from "vue-router"
import XEUtils, { isEmpty } from "xe-utils"
import componentVue from "./components/component.vue"
import FieldTable from "./components/FieldTable.vue"
import StaticFieldTable from "./components/FieldTable.vue"
import "@@/components/plugins/EditDownModal"
import fileList from "./components/fileList.vue"


defineOptions({
  name: "ComponentView"
})

const router = useRouter()
const route = useRoute()
const curId = ref<string>(route.query.id as string)
const fileVisible = ref<boolean>(false)
const fileData = ref([])

const component = ref<BasicDataInfo>({
  id: route.query.id as string,
  name: "",
  code: "",
  tag: [],
  parentId: "",
  description: ""
})
const rules = ref<FormRules>({
  code: [
    { required: true, message: '请输入', trigger: "blur" },
    { message: "第一个字符必须是字母（大小写均可）或下划线 _", pattern: /^[a-zA-Z_][a-zA-Z0-9_]*$/, trigger: "blur" }
  ],
  name: [{ required: true, message: "请输入别名", trigger: "blur" }]
})
const activeTab = ref("table")
const methodTableData = ref<MethodField[]>([])
const componentRef = ref<FormInstance | null>(null)
const parentOptions = ref<{ label: string, value: string, code: string }[]>([])
const fieldTableRef = ref()
const staticFieldTableRef = ref()
const methodTableRef = ref()
const table_toolbar = ref("insertStaticFields")
const isEdit = ref<boolean>(false)

const tableData = ref<BasicClassValueField[]>([])
const staticTableData = ref<BasicClassValueField[]>([])
// 页面新增class参数信息
const insertMethods = ref<MethodField[]>([])
const removeMethods = ref<MethodField[]>([])

const initComInfo = ref<BasicDataInfo>()
const initFieldData = ref<BasicClassValueField[]>([])
const initStaticFieldData = ref<BasicClassValueField[]>([])
const initMethodData = ref<MethodField[]>([])
// 文件名称
const allFiles = ref([
  '文档A.docx',
  '报告B.pdf',
  '图片C.png1111111111111',
  '合同D.doc',
  '演示E.pptx',
  '统计F.xlsx',
  '数据G.json',
  '数据G.json',
  '数据G.json',
  '数据G.json',
  '数据G.json',
  '数据G.json',
  '数据G.json',
  '数据G.jso11',
  '数据G.jso11',
  '数据G.jso11',
  '数据G.jso11',
  '数据G.jso11',
  '数据G.jso11',
  '数据G.jso11',
  '数据G.jso11',
  '数据G.jso11',
  '数据G.jso11',
  '数据G.jso112',
])
const wrapper = ref<any>(null)
const visibleFiles = ref<string[]>([])
const insertFiles = ref([])
const hiddenFiles = ref<string[]>([])

const calculateVisible = async () => {
  await nextTick()
  const containerWidth = wrapper.value.offsetWidth
  let currentWidth = 0
  const visible = []
  const hidden = []

  const tester = document.createElement('span')
  tester.style.visibility = 'hidden'
  tester.style.position = 'absolute'
  tester.style.whiteSpace = 'nowrap'
  tester.style.fontSize = '14px'
  tester.style.padding = '0 8px'
  document.body.appendChild(tester)

  for (let file of allFiles.value) {
    tester.innerText = file
    const width = tester.offsetWidth + 12 // margin
    if (currentWidth + width < containerWidth - 60) {
      visible.push(file)
      currentWidth += width
    } else {
      hidden.push(file)
    }
  }

  document.body.removeChild(tester)
  visibleFiles.value = visible
  hiddenFiles.value = hidden
}
const openFile = (val: any) => {
  window.open('/hubeihuanjing.pdf')
}
const fileCloseDialog = () => {
  fileVisible.value = false
  modelDetail()
}
const DEFAULT_METHOD_VALUE: MethodField = {
  type: undefined,
  // 返回值类型
  returnType: undefined,
  // 函数名
  name: undefined
}
const methodsValidRules = ref<VxeTablePropTypes.EditRules>({
  name: [{ required: true, message: "函数名不能为空", trigger: "blur" }],
  type: [{ required: true, message: "函数类型不能为空", trigger: "blur" }],
  returnType: [{ required: true, message: "返回值类型", trigger: "blur" }]
})

const deleteMethodBtn = computed(() => {
  if (methodTableRef.value) {
    const selectRecords = methodTableRef.value.getCheckboxRecords()
    return selectRecords.length > 0
  }
  return false
})

// 新增成员函数
function handleCreateMethod() {
  const record = cloneDeep(DEFAULT_METHOD_VALUE)
  record.id = uuidv4()
  record.isAdd = true
  methodTableData.value.push(record)
  insertMethods.value.push(record)
  methodTableRef.value.setEditRow(record, "type")
}
// 批量删除成员函数
function handleMulDelMethod() {
  if (methodTableRef.value) {
    const selectRecords = methodTableRef.value.getCheckboxRecords()
    const ids: string[] = []
    const names: string[] = []
    selectRecords.forEach((item) => {
      ids.push(item.id as string)
      names.push(item.name as string)
    })
    ElMessageBox.confirm(`正在删除成员函数：${names.join("，")}，确认删除？`, "提示", {
      confirmButtonText: "确定",
      cancelButtonText: "取消",
      type: "warning"
    }).then(() => {
      const delIds: number[] = []
      XEUtils.eachTree(selectRecords, (item) => {
        if (!removeMethods.value.some(obj => item.id === obj.id)) {
          delIds.push(item.id)
          removeMethods.value.push(item)
        }
      }, { children: "children" })
      methodTableData.value = methodTableData.value.filter(item => !delIds.includes(item.id))
      insertMethods.value = insertMethods.value.filter(item => !delIds.includes(item.id))
    })
  }
}

function handleTopCreateTask() {
  if (table_toolbar.value === "insertFields") {
    fieldTableRef.value.handleAddDialog()
  }
  if (table_toolbar.value === "insertStaticFields") {
    staticFieldTableRef.value.handleAddDialog()
  }
}

// 提交
// async function handleSave() {
//   keepFile()
//   if (!componentRef.value) return false
//   await fieldTableRef.value.handleValidParam()
//   await staticFieldTableRef.value.handleValidParam()

//   componentRef.value.validate().then(() => {
//     const fieldParam = fieldTableRef.value.getFieldParam()
//     const staticFieldParam = staticFieldTableRef.value.getFieldParam()
//     const _methodTableData = cloneDeep(insertMethods.value)
//     _methodTableData.forEach((item) => {
//       delete item.id
//     })
//     keepFile()
//     const compItem = cloneDeep(component.value)
//     compItem.tag = JSON.stringify(compItem.tag)
//     let saveData: SaveRequestData = {
//       component: cloneDeep(compItem),
//       insertFields: fieldParam.insertFields,
//       updateFields: fieldParam.updateFields,
//       removeFields: fieldParam.removeFields,
//       insertStaticFields: staticFieldParam.insertFields,
//       updateStaticFields: staticFieldParam.updateFields,
//       removeStaticFields: staticFieldParam.removeFields,
//       insertMethods: _methodTableData,
//       updateMethods: [],
//       removeMethods: []
//     }
//     delete saveData.component.parentComponent
//     const updateMethods = methodTableRef.value.getUpdateRecords()
//     saveData.updateMethods = updateMethods.filter(item => !item.isAdd)
//     saveData.removeMethods = removeMethods.value.filter(item => !item.isAdd)
//     const fd = new FormData()
//     fd.append("businessParam", JSON.stringify(saveData))
//     saveModelField(fd).then((res) => {
//       ElMessage.success("保存成功")
//       modelDetail()
//       isEdit.value = false
//     }).catch(() => {
//       ElMessage.error("保存失败")
//     })
//   }).catch(() => {
//     return false
//   })
// }
async function handleSave() {
  keepFile()
}
// 退出
function handleCancel() {
  // 关闭当前tab页
  closeRoute()
  router.back()
}
// 保存文件接口
async function keepFile() {
  await fieldTableRef.value.handleValidParam()
  await staticFieldTableRef.value.handleValidParam()

  const newFiles = insertFiles.value.filter(item => !item.id)
  const fd = new FormData()
  newFiles.forEach((item: any, index: any) => {
    fd.append(`insertFiles[${index}].file`, item.raw)
  })
  fd.append("businessId", curId.value)
  removeFile.value.forEach((item: any, index: any) => {
    fd.append(`removeFiles[${index}].id`, item)
  })
  uploadEntityFilesApi(fd).then((res: any) => {
    // 先保存文件，再保存基本信息，保证查看附件能显示出来
    if (!componentRef.value) return false
    componentRef.value.validate().then(() => {
      const fieldParam = fieldTableRef.value.getFieldParam()
      const staticFieldParam = staticFieldTableRef.value.getFieldParam()
      const _methodTableData = cloneDeep(insertMethods.value)
      _methodTableData.forEach((item) => {
        delete item.id
      })
      const compItem = cloneDeep(component.value)
      compItem.tag = JSON.stringify(compItem.tag)
      let saveData: SaveRequestData = {
        component: cloneDeep(compItem),
        insertFields: fieldParam.insertFields,
        updateFields: fieldParam.updateFields,
        removeFields: fieldParam.removeFields,
        insertStaticFields: staticFieldParam.insertFields,
        updateStaticFields: staticFieldParam.updateFields,
        removeStaticFields: staticFieldParam.removeFields,
        insertMethods: _methodTableData,
        updateMethods: [],
        removeMethods: []
      }
      delete saveData.component.parentComponent
      const updateMethods = methodTableRef.value.getUpdateRecords()
      saveData.updateMethods = updateMethods.filter(item => !item.isAdd)
      saveData.removeMethods = removeMethods.value.filter(item => !item.isAdd)
      const fd2 = new FormData()
      fd2.append("businessParam", JSON.stringify(saveData))
      saveModelField(fd2).then((res) => {
        ElMessage.success("保存成功")
        modelDetail()
        isEdit.value = false
      }).catch(() => {
        ElMessage.error("保存失败")
      })
    }).catch(() => {
      return false
    })

  })
}
// 删除文件
const removeFile = ref<string[]>([])
function handleRemove(uploadFile: any, uploadFiles: any) {
  if (uploadFile.id) {
    // 已经存在的文件,获取当前文件id
    removeFile.value.push(uploadFile.id)
  } else {
    /// 如果是新上传的文件，从 insertFiles 中删除
    const index = insertFiles.value.findIndex((file: any) => file.raw === uploadFile.raw)
    if (index !== -1) {
      insertFiles.value.splice(index, 1) // 从 insertFiles 中删除新上传的文件
    }
  }
}
// 附件选中事件
const handleFileChange: UploadProps["onChange"] = (file: any, fileList: any) => {
  insertFiles.value = fileList
}
// 删除节点
function removeNode(id: string) {
  if (table_toolbar.value === "insertFields") {
    fieldTableRef.value.handleRemoveNode(id)
  }
  if (table_toolbar.value === "insertStaticFields") {
    staticFieldTableRef.value.handleRemoveNode(id)
  }
}
function handleChangeToolbar(value: string) {
  table_toolbar.value = value
}
function updateData(params: BasicClassValueField[]) {
  tableData.value = cloneDeep(params)
}
function updateStaticData(params: BasicClassValueField[]) {
  staticTableData.value = cloneDeep(params)
}

function handleEditDialog(data: BasicClassValueField) {
  if (table_toolbar.value === "insertFields") {
    fieldTableRef.value.handleEditDialog(data)
  }
  if (table_toolbar.value === "insertStaticFields") {
    staticFieldTableRef.value.handleEditDialog(data)
  }
}

// Store initial form data when entering edit mode
function handleEdit() {
  isEdit.value = true
}

// Cancel save handler
function handleCancelSave() {
  fieldTableRef.value.clearData()
  staticFieldTableRef.value.clearData()
  fieldTableRef.value.initFieldData(initFieldData.value)
  staticFieldTableRef.value.initFieldData(initStaticFieldData.value)

  insertMethods.value = []
  removeMethods.value = []
  methodTableData.value = cloneDeep(initMethodData.value)

  isEdit.value = false
}

function modelDetail() {
  // 初始化详情
  getModelDetail(curId.value).then(({ data }) => {
    component.value = data.component
    component.value.tag = isEmpty(data.component.tag) ? [] : JSON.parse(data.component.tag as string)
    component.value.parentComponent = data.component.parentComponent
    const fieldList: BasicClassValueField[] = []
    const staticFieldList: BasicClassValueField[] = []
    data.fields.forEach((item) => {
      if (item.staticFlag === 0) {
        fieldList.push(item)
      } else {
        staticFieldList.push(item)
      }
    })
    fieldTableRef.value.initFieldData(fieldList)
    staticFieldTableRef.value.initFieldData(staticFieldList)
    methodTableData.value = cloneDeep(data.methods)

    initComInfo.value = cloneDeep(component.value)
    initFieldData.value = cloneDeep(fieldList)
    initStaticFieldData.value = cloneDeep(staticFieldList)
    initMethodData.value = cloneDeep(methodTableData.value)
    fileData.value = data.files
    insertFiles.value = data.files.map((file:any) => ({
      ...file,
      name: file.fileName
    }))
    handleCancelSave()
  })
  getModelSearch({}).then(({ data }) => {
    parentOptions.value = data.rows.filter(item => item.name && item.id)
      .map(item => ({
        label: item.name!,
        code: item.code,
        value: item.id!
      }))
  })
}
const fileClick = () => {
  fileVisible.value = !fileVisible.value
}
// const handleFileChange: UploadProps["onChange"] = (file: any, fileList: any) => {
//   insertFiles.value.push(file)
// }

// 获取组件模型列表
onMounted(() => {
  modelDetail()
  calculateVisible()
  window.addEventListener('resize', calculateVisible)
})
onActivated(() => {
  if (curId.value && curId.value !== route.query.id) {
    isEdit.value = false
    activeTab.value = 'table'
    curId.value = route.query.id as string
    modelDetail()
  }
})
</script>

<template>
  <div class="app-container pager-container">
    <div class="app-container-content">
      <div class="cpi-header">
        <span class="cpi-header-text">基本信息</span>
        <el-button @click="handleEdit" :icon="Edit" class="edit" v-if="!isEdit">
          编辑
        </el-button>
        <div v-if="isEdit">
          <el-button @click="handleCancelSave">
            取消保存
          </el-button>
          <el-button type="primary" v-throttle="() => handleSave()">
            保存
          </el-button>
        </div>
      </div>
      <div class="basic-data-create-table" v-if="isEdit">
        <el-form ref="componentRef" :model="component" status-icon :rules="rules" label-position="right"
          label-width="85" class="demo-component">
          <el-row :gutter="24">
            <el-col :sm="12" :lg="6">
              <el-form-item label="名称" prop="code">
                <el-input v-model="component.code" placeholder="请输入" autocomplete="off" />
              </el-form-item>
            </el-col>
            <el-col :sm="12" :lg="6">
              <el-form-item label="别名" prop="name">
                <el-input v-model="component.name" placeholder="请输入" autocomplete="off" />
              </el-form-item>
            </el-col>
            <el-col :sm="12" :lg="6">
              <el-form-item label="标签" prop="tag">
                <SelectTag module="component" v-model:task_tags="component.tag" :max-collapse-tags="2" />
              </el-form-item>
            </el-col>
            <el-col :sm="12" :lg="6">
              <el-form-item label="父类" prop="parentId">
                <el-select v-model="component.parentId" filterable placeholder="请选择" style="width: 100%">
                  <el-option v-for="item in parentOptions" :key="item.value" :label="`${item.label}/${item.code}`"
                    :value="item.value" />
                </el-select>
              </el-form-item>
            </el-col>
            <el-col :sm="24" :lg="12">
              <el-form-item label="描述" prop="description">
                <el-input v-model="component.description" type="textarea" show-word-limit maxlength="200"
                  placeholder="请输入" autocomplete="off" />
              </el-form-item>
            </el-col>
          </el-row>
        </el-form>
      </div>

      <el-form v-else label-position="right" class="custom-view-form_nobreak" label-width="85">
        <el-row :gutter="24">
          <el-col :sm="12" :lg="6">
            <el-form-item label="名称：">
              <span :title="$getViewText(component.code)">{{ $getViewText(component.code) }}</span>
            </el-form-item>
          </el-col>
          <el-col :sm="12" :lg="6">
            <el-form-item label="别名：">
              <span :title="$getViewText(component.name)">{{ $getViewText(component.name) }}</span>
            </el-form-item>
          </el-col>
          <el-col :sm="12" :lg="6">
            <el-form-item label="标签：">
              <el-tag v-for="item in component.tag">
                {{ item }}
              </el-tag>
            </el-form-item>
          </el-col>
          <el-col :sm="12" :lg="6">
            <el-form-item label="父类：">
              <span :title="$getViewText(component.parentComponent?.code)">{{
                $getViewText(component.parentComponent?.code) }}</span>
            </el-form-item>
          </el-col>
          <el-col :sm="24">
            <el-form-item label="描述：">
              <span :title="$getViewText(component.description)">{{ $getViewText(component.description) }}</span>
            </el-form-item>
          </el-col>
        </el-row>
      </el-form>

      <div class="cpi-header">
        <span class="cpi-header-text">参数集</span>
        <span class="cpi-header-text-right">
          <span class="cpi-header-text-right-text" @click="activeTab = 'table'"
            :class="{ active: activeTab === 'table' }">表格</span>
          <span class="cpi-header-text-right-text" @click="activeTab = 'topology'"
            :class="{ active: activeTab === 'topology' }">拓扑</span>
        </span>
      </div>

      <div class="cpi-content" v-show="activeTab === 'table'">
        <div class="table_toolbar">
          <span :class="{ active: table_toolbar === 'insertStaticFields' }"
            @click="() => table_toolbar = 'insertStaticFields'">
            静态参数集
          </span>
          <span :class="{ active: table_toolbar === 'insertFields' }"
            @click="() => table_toolbar = 'insertFields'">属性集</span>
        </div>

        <FieldTable v-show="table_toolbar === 'insertFields'" ref="fieldTableRef" :static-flag="0" :is-edit="isEdit"
          @update-data="updateData" />
        <StaticFieldTable v-show="table_toolbar === 'insertStaticFields'" ref="staticFieldTableRef" :static-flag="1"
          :is-edit="isEdit" @update-data="updateStaticData" />
      </div>

      <div class="cpi-content" v-if="activeTab === 'topology'">
        <componentVue :is-edit="isEdit" :handle-create-task="handleTopCreateTask"
          :table_toolbar_clk="handleChangeToolbar" :table_toolbar="table_toolbar"
          :father-data="table_toolbar === 'insertFields' ? tableData : staticTableData" :admin-user="component.code"
          :handle-remove-node="removeNode" :handle-edit="handleEditDialog" />
      </div>

      <div class="cpi-header" style="margin-top: var(--main-padding);">
        <span class="cpi-header-text">成员函数</span>
      </div>
      <div class="cpi-content">
        <div v-if="isEdit" class="cpi-content-toolbar mb-3">
          <el-space>
            <el-button type="primary" plain @click="handleCreateMethod()">
              新建函数
            </el-button>
            <el-button :disabled="!deleteMethodBtn" type="danger" @click="handleMulDelMethod">
              批量删除
            </el-button>
          </el-space>
        </div>
        <div class="cpi-content-main">
          <vxe-table class="cpi-table" ref="methodTableRef" height="auto" show-overflow highlight-hover-row show-header
            auto-resize keep-source size="small" :edit-rules="methodsValidRules" :data="methodTableData"
            :mouse-config="{ selected: false }" :edit-config="{ trigger: 'click', mode: 'row', showStatus: true }">
            <vxe-table-column :visible="isEdit" type="checkbox" width="40" />
            <vxe-table-column type="seq" title="序号" align="center" width="60" />
            <vxe-table-column field="type" title="类型">
              <template #default="{ row }">
                <el-select v-if="isEdit" v-model="row.type" placeholder="请选择">
                  <el-option v-for="item in ['static', 'virtual', 'normal']" :key="item" :label="item" :value="item" />
                </el-select>
                <span v-else>{{ row.type }}</span>
              </template>
            </vxe-table-column>
            <vxe-table-column field="returnType" title="返回类型">
              <template #default="{ row }">
                <el-input v-if="isEdit" v-model="row.returnType" />
                <span v-else>{{ row.returnType }}</span>
              </template>
            </vxe-table-column>
            <vxe-table-column field="name" title="函数名称">
              <template #default="{ row }">
                <el-input v-if="isEdit" v-model="row.name" />
                <span v-else>{{ row.name }}</span>
              </template>
            </vxe-table-column>
          </vxe-table>
        </div>
      </div>
      <el-row :gutter="24" v-if="isEdit">
        <el-col :span="12">
          <div class="form-title form-title-text" style="margin-top: 10px;">
            附件
          </div>
          <div>
            <el-upload class="again-upload" :show-file-list="true" :auto-upload="false"
              action="https://your-upload-api.com/upload" ref="upload" :file-list="insertFiles"
              accept=".zip, .pdf, .doc , .docx" :on-remove="handleRemove" :on-change="handleFileChange"
              :multiple="true">
              <el-button type="success">
                添加附件
              </el-button>
            </el-upload>
          </div>
        </el-col>
      </el-row>
      <div v-else style="margin-top: 5px;cursor: pointer;" @click.stop="fileClick">
        <SvgIcon name="fujian" style="display: inline-block;text-align: center;width: 60px;" :size="6" />
        <span style="display: inline-block;width: 100%;font-size: 14px;margin-top: 10px;">查看附件</span>
      </div>
    </div>
    <div class="pager-wrapper center">
      <el-button @click="handleCancel">
        退出
      </el-button>
    </div>
    <fileList ref="editModelRef" :id="curId" :visible="fileVisible" :file-data="fileData"
      @close-dialog="fileCloseDialog">
    </fileList>
  </div>
</template>

<style lang="scss" scoped>
@import "@@/assets/styles/main-page.scss";
@import "@@/assets/styles/mixins.scss";

.app-container-content {
  flex: 1;
  overflow-y: auto;
  overflow-x: hidden;
  padding-right: 10px;
  @extend %scrollbar;
}

.bac-tabs {
  :deep(.el-tabs__item:hover) {
    color: #409eff !important;
  }

  :deep(.el-tabs__item.is-active:hover) {
    color: white;
  }

  :deep(.el-tabs__item.is-active) {
    background-color: #409eff !important;
    color: white !important;
  }
}

.basic-data-create-footer {
  position: fixed;
  bottom: 0;
  height: 50px;
  left: 0;
  right: 0;
  z-index: 1000;
  width: calc(100vw - 250px);
  background: #000b15;
  display: flex;
  margin-left: 218px;
  justify-content: center;
  align-items: center;
  // margin-top: 20px;
}

.table_toolbar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 10px;
  height: 40px;

  span {
    height: 100%;
    flex: 1;
    text-align: center;
    line-height: 40px;
    border: 1px solid var(--el-border-color-light);
    cursor: pointer;

    &:hover {
      color: #409eff !important;
    }
  }

  span.active {
    background-color: #409eff !important;
    color: white;

    &:hover {
      color: white !important;
    }
  }
}

.file-list {
  cursor: pointer;
  display: flex;
  align-items: center;
  overflow: hidden;
  white-space: nowrap;
  padding: 4px 8px;
  // border: 1px solid rgb(255, 255, 255,.5);
  border-radius: 2px;
}

.file-name {
  margin-right: 12px;
  white-space: nowrap;
  font-size: 14px;

  &:hover {
    color: rgb(0, 187, 153); // 添加背景色
  }
}

.more {
  cursor: pointer;
  color: #FFF;
  font-size: 20px;
  white-space: nowrap;
}

.popover-content {
  cursor: pointer;

  &:hover {
    color: rgb(0, 187, 153); // 添加背景色
  }
}
</style>
